#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#       fasta.py
#       
#       Copyright 2010 Brandon Invergo <brandon@brandoninvergo.com>
#       
#       This program is free software; you can redistribute it and/or modify
#       it under the terms of the GNU General Public License as published by
#       the Free Software Foundation; either version 2 of the License, or
#       (at your option) any later version.
#       
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#       
#       You should have received a copy of the GNU General Public License
#       along with this program; if not, write to the Free Software
#       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#       MA 02110-1301, USA.


from gettext import gettext as _

import gtk
import gedit

# Menu item example, insert a new item in the Tools menu
ui_str = """<ui>
  <menubar name="MenuBar">
    <menu name="EditMenu" action="Edit">
      <placeholder name="EditOps_2">
        <menuitem name="FASTA" action="FASTA"/>
      </placeholder>
    </menu>
  </menubar>
</ui>
"""
class FASTAWindowHelper:
    def __init__(self, plugin, window, width):
        self._window = window
        self._plugin = plugin
        # Insert menu items
        self._insert_menu()
        self._width = width

    def deactivate(self):
        # Remove any installed menu items
        self._remove_menu()
        self._window = None
        self._plugin = None
        self._action_group = None

    def _insert_menu(self):
        # Get the GtkUIManager
        manager = self._window.get_ui_manager()
        # Create a new action group
        self._action_group = gtk.ActionGroup("FASTAPluginActions")
        self._action_group.add_actions([("FASTA", None, _("FASTA clean-up"),
                                         None, _("Clean up a document in FASTA format"),
                                         self.on_format_document_activate)])
        # Insert the action group
        manager.insert_action_group(self._action_group, -1)
        # Merge the UI
        self._ui_id = manager.add_ui_from_string(ui_str)

    def _remove_menu(self):
        # Get the GtkUIManager
        manager = self._window.get_ui_manager()
        # Remove the ui
        manager.remove_ui(self._ui_id)
        # Remove the action group
        manager.remove_action_group(self._action_group)
        # Make sure the manager updates
        manager.ensure_update()

    def update_ui(self):
        self._action_group.set_sensitive(self._window.get_active_document() != None)

    # Menu activate handlers
    def on_format_document_activate(self, action):
        doc = self._window.get_active_document()
        view = self._window.get_active_view()
        if not doc:
            return
        start_iter = doc.get_start_iter()
        end_iter = doc.get_end_iter()
        # Get all the text in the document
        text = doc.get_text(start_iter, end_iter)
        # Split the text by lines
        text_lines = text.split('\n')
        # String to hold the new text
        text_new = ""
        # Placeholder string to store a line in progress
        sequence = ""
        for line in text_lines:
            line = line.strip()
            # Skip blank lines
            if line is "":
                continue
            # Header lines should be skipped after writing any sequence 
            # text remaining    
            if line[0] is '>':
                if sequence is not "":
                    text_new += sequence + '\n'
                    sequence = ""
                text_new += line + '\n'
                continue
            line = line.replace(" ", "")
            line = line.upper()
            start = 0
            # Slide a window along the line taking as many characters
            # as necessary/possible to fill the placeholder string and
            # copy the placeholder string to the new text string when it
            # fills
            while start < len(line):
                end = start + self._width - len(sequence)
                if end > len(line):
                    end = len(line)
                sequence += line[start:end]
                if len(sequence) is self._width:
                    text_new += sequence + '\n'
                    sequence = ""
                start = end
        if sequence is not "":
            text_new += sequence + '\n'
        insert = doc.get_mark("insert")
        doc.set_text(text_new.strip())
        view.scroll_to_mark(insert)
        
    def set_width(self, width):
        # Set the number of characters per line
        self._width = width
        
class FASTAPlugin(gedit.Plugin):
    def __init__(self):
        gedit.Plugin.__init__(self)
        self._instances = {}
        self._width = 60

    def activate(self, window):
        self._instances[window] = FASTAWindowHelper(self, window, self._width)

    def deactivate(self, window):
        self._instances[window].deactivate()
        del self._instances[window]

    def update_ui(self, window):
        self._instances[window].update_ui()

    def is_configurable(self):
        return True
    
    def create_configure_dialog(self):
        dialog = gtk.Dialog("FASTA Plugin Configuration", None, 0,
            (gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))
        width_label = gtk.Label("Width (# of characters):  ")
        self._width_spin = gtk.SpinButton()
        self._width_spin.set_range(40, 120)
        self._width_spin.set_value(self._width)
        self._width_spin.set_increments(1,5)
        self._width_spin.set_update_policy(gtk.UPDATE_IF_VALID)
        self._width_spin.set_numeric(True)
        width_hbox = gtk.HBox()
        width_hbox.pack_start(width_label)
        width_hbox.pack_start(self._width_spin)
        width_label.show()
        self._width_spin.show()
        dialog.vbox.pack_start(width_hbox)
        width_hbox.show()
        dialog.connect("response", self.on_response)
        self.dialog = dialog
        return dialog
        
    def on_response(self, dialog, response_id):
        width = self._width_spin.get_value_as_int()
        if width > 120:
            width = 120
        elif width < 40:
            width = 40
        self._width = width
        for window in self._instances.keys():
            self._instances[window].set_width(width)
        self.dialog.hide()
